/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package taquin_console;

import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Caroline
 */
public class Grille implements Cloneable {

    private int taille;
    private int[][] cases;
    private int poids = 0;
    private int niveau;
    private int[] positionVide;

    public Grille(int taille) {
        this.cases = new int[taille][taille];
        this.positionVide = new int[2];
        this.taille = taille;
    }

    public int[] getPositionVide() {
        return positionVide;
    }

    public void setPositionVide(int i, int j) {
        positionVide[0] = i;
        positionVide[1] = j;
    }

    public int getTaille() {
        return taille;
    }

    public void setTaille(int tailles) {
        taille = tailles;
    }

    public int[][] getCases() {
        return cases;
    }

    public int getCase(int i, int j) {
        return cases[i][j];
    }

    public void setCases(int[][] casess) {
        cases = casess;
    }

    public int getNiveau() {
        return niveau;
    }

    public void setNiveau(int niveaux) {
        niveau = niveaux;
    }

    public int getPoids() {
        return poids;
    }

    public void setPoids(int poid) {
        poids = poid;
    }

    public void setCase(int i, int j, int val) {
        cases[i][j] = val;
    }

    public Grille deplacerVideBas() throws CloneNotSupportedException {
        int[] pv = getPositionVide();
        if (pv[0] != taille - 1) {

            Grille g = (Grille) this.clone();
            g.setNiveau(g.getNiveau() + 1);

            int tmp = getCase(pv[0] + 1, pv[1]);
            g.setCase(pv[0] + 1, pv[1], 0);
            g.setCase(pv[0], pv[1], tmp);
            g.setPositionVide(pv[0] + 1, pv[1]);


            return g;
        }
        return null;
    }

    public Grille deplacerVideHaut() throws CloneNotSupportedException {
        int[] pv = this.getPositionVide();
        if (pv[0] != 0) {

            Grille g = (Grille) this.clone();
            g.setNiveau(g.getNiveau() + 1);

            int tmp = g.getCase(pv[0] - 1, pv[1]);

            g.setCase(pv[0] - 1, pv[1], 0);
            g.setCase(pv[0], pv[1], tmp);
            g.setPositionVide(pv[0] - 1, pv[1]);

            return g;
        }
        return null;
    }

    public Grille deplacerVideGauche() throws CloneNotSupportedException {
        int[] pv = getPositionVide();
        if (pv[1] != 0) {

            Grille g = (Grille) this.clone();
            g.setNiveau(g.getNiveau() + 1);
            int tmp = g.getCase(pv[0], pv[1] - 1);

            g.setCase(pv[0], pv[1] - 1, 0);
            g.setCase(pv[0], pv[1], tmp);
            g.setPositionVide(pv[0], pv[1] - 1);

            return g;
        }
        return null;
    }

    public Grille deplacerVideDroite() throws CloneNotSupportedException {
        int[] pv = getPositionVide();
        if (pv[1] != taille - 1) {

            Grille g = (Grille) this.clone();
            g.setNiveau(g.getNiveau() + 1);
            int tmp = getCase(pv[0], pv[1] + 1);

            g.setCase(pv[0], pv[1] + 1, 0);
            g.setCase(pv[0], pv[1], tmp);
            g.setPositionVide(pv[0], pv[1] + 1);

            return g;
        }
        return null;
    }

    public int setHeuristique(Heuristique h, Grille ef) {

        switch (h) {
            case P:
                this.setPoids(heuristiqueP(ef));
                break;
            case W:
                this.setPoids(heuristiqueW(ef));
                break;
            case P3S:
                this.setPoids(heuristiqueP3S(ef));
                break;

        }
        return 0;
    }

    public int heuristiqueW(Grille ef) {
        int p = 0;
        int c, e;
        for (int i = 0; i < taille; i++) {
            for (int j = 0; j < taille; j++) {
                c = this.getCase(i, j);
                e = ef.getCase(i, j);
                if (c != e) {
                    p += 1;
                }
            }
        }
        return p;
    }

    //heuristique sur la distance de Manhattan
    public int heuristiqueP(Grille ef) {
        //recuperer la position de chaque case
        //calculer la distance entre la position initiale et la position finale
        //retour de l'entier
        int dist = 0;
        for (int x = 0; x < this.getTaille(); x++) {
            for (int y = 0; y < this.getTaille(); y++) {
                dist += Math.abs(this.getCase(x, y) - ef.getCase(x, y));

            }
        }
        return dist;
    }

    public int heuristiqueP3S(Grille ef) {
        int p = 0;
        //calcul de la suivante

        if (this.getCase(0, 0) != ef.getCase(0, 1)) {
            p += 2;
        }
        if (this.getCase(0, 1) != ef.getCase(0, 2)) {
            p += 2;
        }
        if (this.getCase(0, 2) != ef.getCase(1, 2)) {
            p += 2;
        }
        if (this.getCase(1, 2) != ef.getCase(2, 2)) {
            p += 2;
        }
        if (this.getCase(2, 2) != ef.getCase(2, 1)) {
            p += 2;
        }
        if (this.getCase(2, 1) != ef.getCase(2, 0)) {
            p += 2;
        }
        if (this.getCase(2, 0) != ef.getCase(1, 0)) {
            p += 2;
        }
        if (this.getCase(1, 0) != ef.getCase(0, 0)) {
            p += 2;
        }
        if (this.getCase(1, 1) != ef.getCase(1, 1)) {
            p += 1;

        }

        p = 3 * p;
        p += heuristiqueW(ef);
        return p;
    }



    public String toString() {
        String s = "";
        for (int i = 0; i < taille; i++) {
            for (int j = 0; j < taille; j++) {
                s += cases[i][j] + " ";
            }
            s += "\n";
        }

        return s + "\nNiveau =" + niveau + " || Poids = " + poids + "\n";
    }

    public Object clone() {
        Grille grille = null;
        try {
            // On récupère l'instance à renvoyer par l'appel de la 
            // méthode super.clone()
            grille = (Grille) super.clone();
        } catch (CloneNotSupportedException cnse) {
            // Ne devrait jamais arriver car nous implémentons 
            // l'interface Cloneable
            cnse.printStackTrace(System.err);
        }

        // On clone l'attribut de type Patronyme qui n'est pas immuable.
        grille.cases = (int[][]) cases.clone();
        for (int i = 0; i < taille; i++) {
            grille.cases[i] = (int[]) cases[i].clone();
        }

        grille.positionVide = (int[]) positionVide.clone();

        // on renvoie le clone
        return grille;
    }
}
